package ldk.easytouch.example.helper;

import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.text.TextUtils;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

import ldk.easytouch.interfaces.ResultCallback;
import ldk.easytouch.utils.ETLog;

/**
 * Created by ke on 16-9-16.
 */
public class RecentTaskHelper {
    @SuppressWarnings("unused")
    private static final String TAG = "RecentTaskHelper";

    private Handler mUIHandler, mWorkerHandler;
    private Context mContext;
    private int mRefreshTime = 3000; // negative is in launcher
    private ResultCallback<Boolean> mInLauncherCallback;

    private static final int WORKER_GET_IS_IN_LAUNCHER = 1;
    private static final int WORKER_REFRESH = 2;
    private static final int WORKER_CLEAN_BACKGROUND_PROGRESS = 3;

    private static final int UI_IS_IN_LAUNCHER = 1;
    private static final int UI_CLEAN_BACKGROUND_PROGRESS = 2;

    private static final String[] s_Launcher_list = new String[]{
            "com.android.launcher3", "com.meizu.flyme.launcher"
    };

    private static RecentTaskHelper s_Instance;

    public static RecentTaskHelper getInstance(){
        return s_Instance;
    }

    public RecentTaskHelper(Context context, ResultCallback<Boolean> callback){
        mContext = context;
        mInLauncherCallback = callback;
        HandlerThread worker = new HandlerThread(TAG, Thread.NORM_PRIORITY);
        worker.start();
        mUIHandler = new UIHandler();
        mWorkerHandler = new WorkerHandler(worker.getLooper());
        s_Instance = this;
    }

    private class WorkerHandler extends Handler{

        public WorkerHandler(Looper looper){
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            removeMessages(msg.what);
            switch (msg.what){
                case WORKER_GET_IS_IN_LAUNCHER:
                    boolean isInLauncher = isInLauncher();
                    ETLog.v(TAG, "isInLauncher is " + isInLauncher + ", and refreshTime is " + mRefreshTime);
                    Message message = mUIHandler.obtainMessage(UI_IS_IN_LAUNCHER);
                    message.obj = isInLauncher;
                    mUIHandler.sendMessage(message);
                    break;
                case WORKER_REFRESH:
                    sendEmptyMessageDelayed(WORKER_REFRESH, Math.abs(mRefreshTime));
                    sendEmptyMessage(WORKER_GET_IS_IN_LAUNCHER);
                    break;
                case WORKER_CLEAN_BACKGROUND_PROGRESS:
                    cleanBackgroundProgressInternal();
                    break;
                default:
                    ETLog.v(TAG, "not handle message, and what is %d.", msg.what);
            }
        }
    }

    public void onResume(){
        mWorkerHandler.sendEmptyMessage(WORKER_REFRESH);
        ETLog.v(TAG, "onResume");
    }

    public void onStop(){
        mWorkerHandler.removeMessages(WORKER_REFRESH);
        ETLog.v(TAG, "onStop");
    }

    private boolean isInLauncher(){
        String lastPackageName;
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
            lastPackageName = getLastPackageName();
        }else{
            lastPackageName = getLastPackageNameOld();
        }

        boolean result = TextUtils.isEmpty(lastPackageName) && mRefreshTime < 0;
        if(mContext.getPackageName().equals(lastPackageName)){
            result = true;
        }else {
            for(String launcherPackageName : s_Launcher_list){
                if(launcherPackageName.equals(lastPackageName)){
                    result = true;
                    break;
                }
            }
        }
        if(result){
            if(mRefreshTime < 0){
                mRefreshTime *= 2;
                mRefreshTime = Math.max(mRefreshTime, -300000);
            }
            else mRefreshTime = -3000;
        }else{
            if(mRefreshTime > 0){
                mRefreshTime *= 2;
                mRefreshTime = Math.min(mRefreshTime, 300000);
            }
            else mRefreshTime = 3000;
        }
        return result;
    }

    public void cleanBackgroundProgress(){
        mWorkerHandler.sendEmptyMessage(WORKER_CLEAN_BACKGROUND_PROGRESS);
    }

    private void cleanBackgroundProgressInternal(){
        ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
        PackageManager packageManager = mContext.getPackageManager();
        List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfoList = activityManager.getRunningAppProcesses();
        for(ActivityManager.RunningAppProcessInfo runningAppProcessInfo : runningAppProcessInfoList){
            String packageName = runningAppProcessInfo.processName;
            if(mContext.getPackageName().equals(packageName)) continue;
            try {
                ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0);
                boolean isSystemApp = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1;
                ETLog.v(TAG, "running progress: %s, and isSystemApp: %b", packageName, isSystemApp);
                if(!isSystemApp){
                    // need kill progress
                    Message uiMessage = mUIHandler.obtainMessage(UI_CLEAN_BACKGROUND_PROGRESS);
                    uiMessage.obj = killProgressWithRoot(packageName);
                    mUIHandler.sendMessage(uiMessage);
                }
            } catch (PackageManager.NameNotFoundException e) {
                if(packageName.contains(":")){
                    ETLog.v(TAG, "service process: %s", packageName);
                }else{
                    ETLog.e(TAG, e.getMessage(), e);
                }
            } catch (IOException e) {
                ETLog.e(TAG, "kill progress need root permission" + e.getMessage(), e);
            }
        }
    }

    private boolean killProgressWithRoot(String packageName) throws IOException {
        Process suProcess = Runtime.getRuntime().exec("su");
        DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
        DataInputStream osRes = new DataInputStream(suProcess.getInputStream());
        os.writeBytes("id\n");
        os.flush();

        String currUid = osRes.readLine();
        if(TextUtils.isEmpty(currUid) || !currUid.contains("uid=0")){
            ETLog.v(TAG, "kill progress need root permission");
            return false;
        }

        os.writeBytes("adb shell \n");
        os.flush();
        os.writeBytes("am force-stop " + packageName + "\n");
        os.flush();
        os.close();
        suProcess.destroy();
        ETLog.v(TAG, "killProgressWithRoot %s", packageName);
        return true;
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private String getLastPackageName(){
        List<UsageStats> usageStatsList = getUsageStatsList(100);
        if(usageStatsList == null || usageStatsList.isEmpty()){
            ETLog.e(TAG, "usageList is null or empty", null);
            return "";
        }
        return usageStatsList.get(0).getPackageName();
    }

    private String getLastPackageNameOld(){
        List<ActivityManager.RecentTaskInfo> infoList = getRecentTaskOld();
        if(infoList == null || infoList.isEmpty()) return "";
        return infoList.get(0).baseIntent.getComponent().getPackageName();
    }

    private List<ActivityManager.RecentTaskInfo> getRecentTaskOld(){
        ActivityManager manager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
        return manager.getRecentTasks(10, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
    }



    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public void showCurrentTask(){
        List<UsageStats> usageStatsList = getUsageStatsList(100);
        if(usageStatsList == null){
            ETLog.v(TAG, "showCurrentTask, and usageStatsList is null");
            gotoUsageStatsActivity();
            return;
        }

        StringBuilder builder = new StringBuilder();
        for(UsageStats stats : usageStatsList){
            builder.append("time: ").append(stats.getLastTimeUsed())
                    .append("\t package name is ").append(stats.getPackageName())
                    .append("\n");
        }
        ETLog.v(TAG, "showCurrentTask: \n%s", builder.toString());
    }

    public void showRecentTask(){
        ActivityManager manager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RecentTaskInfo> infoList = manager.getRecentTasks(10, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
        StringBuilder builder = new StringBuilder();
        for(ActivityManager.RecentTaskInfo info : infoList){
            builder.append("packageName is : ").append(info.baseIntent.getComponent().getPackageName()).append("\n");
        }
        ETLog.v(TAG, "showRecentTask,\n %s", builder.toString());
    }

    private void gotoUsageStatsActivity(){
        Intent intent = new Intent();
        intent.setAction(Settings.ACTION_USAGE_ACCESS_SETTINGS);
        mContext.startActivity(intent);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @NonNull
    private List<UsageStats> getUsageStatsList(int seconds){
        UsageStatsManager usageStatsManager
                = (UsageStatsManager) mContext.getSystemService(Context.USAGE_STATS_SERVICE);
        long time = System.currentTimeMillis();
        List<UsageStats> stats = usageStatsManager.queryUsageStats(
                UsageStatsManager.INTERVAL_DAILY, time - seconds * 1000, time);
        if(stats != null){
            SortedMap<Long, UsageStats> sortedMap = new TreeMap<>();
            for(UsageStats stat : stats){
                sortedMap.put(stat.getLastTimeUsed(), stat);
            }
            if(sortedMap.isEmpty()) return null;
            List<UsageStats> result = new ArrayList<>();
            List<Long> keyList = new ArrayList<>(sortedMap.keySet());
            Collections.sort(keyList, new Comparator<Long>() {
                @Override
                public int compare(Long o1, Long o2) {
                    if(o1 < o2) return 1;
                    if(o1.equals(o2)) return 0;
                    return -1;
                }
            });
            for(Long key : keyList){
                result.add(sortedMap.get(key));
            }
            return result;
        }
        return null;
    }


    private class UIHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case UI_IS_IN_LAUNCHER:
                    removeMessages(UI_IS_IN_LAUNCHER);
                    if(mInLauncherCallback != null) mInLauncherCallback.onResult(0, (Boolean) msg.obj);
                    break;
            }
        }
    }
}
